package com.sunwayworld.basemodule.business.result.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.basemodule.business.operationbatch.bean.LimsOrderTaskSupplementBean;
import com.sunwayworld.basemodule.business.operationbatch.service.LimsOrderTaskSupplementService;
import com.sunwayworld.basemodule.business.ordertask.bean.LimsOrderTaskBean;
import com.sunwayworld.basemodule.business.result.bean.LimsResultBean;
import com.sunwayworld.basemodule.business.result.bean.LimsResultDTO;
import com.sunwayworld.basemodule.business.result.computing.OrderTaskResultComputingEngine;
import com.sunwayworld.basemodule.business.result.dao.LimsResultDao;
import com.sunwayworld.basemodule.business.result.service.LimsResultService;
import com.sunwayworld.basemodule.coredata.test.bean.LimsPossibleResultBean;
import com.sunwayworld.basemodule.coredata.test.bean.LimsTestMethodAnalyteBean;
import com.sunwayworld.basemodule.coredata.test.bean.LimsTestSupplementBean;
import com.sunwayworld.basemodule.coredata.test.service.LimsPossibleResultService;
import com.sunwayworld.basemodule.coredata.test.service.LimsTestMethodAnalyteService;
import com.sunwayworld.basemodule.coredata.test.service.LimsTestSupplementService;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.constant.Constant;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.data.page.Page;
import com.sunwayworld.framework.data.page.Pagination;
import com.sunwayworld.framework.mybatis.mapper.MapperParameter;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.mybatis.page.PageRowBounds;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.utils.BeanUtils;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.StringUtils;
import com.sunwayworld.module.sys.at.bean.CoreAuditTrailRecordLineBean;
import com.sunwayworld.module.sys.at.service.CoreAuditTrailRecordLineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsResultServiceImpl implements LimsResultService {

    @Autowired
    private LimsResultDao limsResultDao;

    @Lazy
    @Autowired
    private LimsTestMethodAnalyteService analyteService;

    @Lazy
    @Autowired
    private LimsPossibleResultService possibleResultService;

    @Lazy
    @Autowired
    private CoreAuditTrailRecordLineService coreAuditTrailRecordLineService;

    @Lazy
    @Autowired
    private LimsOrderTaskSupplementService orderTaskSupplementService;

    @Lazy
    @Autowired
    private LimsTestSupplementService testSupplementService;

    @Override
    @SuppressWarnings("unchecked")
    public LimsResultDao getDao() {
        return limsResultDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsResultBean limsResult = jsonWrapper.parseUnique(LimsResultBean.class);
        limsResult.setId(ApplicationContextHelper.getNextIdentity());
        getDao().insert(limsResult);
        return limsResult.getId();
    }

    @Override
    /*
     * 分析项继承标记为是才继承，默认为是
     * */
    public void copyOrderTaskInfoToResult(Long testId, List<Long> testMethodIds, List<LimsOrderTaskBean> orderTaskList) {
        if (orderTaskList.isEmpty()) {
            return;
        }
        // 获取工序分析项，而不是模板分析项
        List<LimsResultBean> insertList = new ArrayList<>();
        List<LimsTestMethodAnalyteBean> analyteList = analyteService.selectListByFilter(SearchFilter.instance()
                .match("testMethodId", testMethodIds).filter(MatchPattern.OR));
        orderTaskList.forEach(orderTask -> {
            List<LimsTestMethodAnalyteBean> analyteInOrderTaskList = analyteList.stream().filter(analyteBean -> analyteBean.getTestMethodId().equals(orderTask.getTestMethodId())).collect(Collectors.toList());
            // 得到该样品的分析项
            insertList.addAll(getResultByOrderTaskAndAnalyte2(orderTask, analyteInOrderTaskList));
        });

        if (!insertList.isEmpty()) {
            List<Long> ids = ApplicationContextHelper.getNextIdentityList(insertList.size());
            int index = 0;
            for (LimsResultBean resultBean : insertList) {
                resultBean.setId(ids.get(index++));
            }
            List<Long> orderTaskIds = orderTaskList.parallelStream().map(LimsOrderTaskBean::getId).distinct().collect(Collectors.toList());
            // 查找当前工序的补充信息，将相同结果同步过来
            List<LimsOrderTaskSupplementBean> orderTaskSupplementBeans = orderTaskSupplementService.getDao().selectListByOneColumnValues(orderTaskIds, "orderTaskId")
                    .stream().filter(e -> !StringUtils.isBlank(e.getFieldValue())).collect(Collectors.toList());
            // 过滤掉不需要带入到分析项的补充信息
            List<LimsTestSupplementBean> testSupplementBeans = testSupplementService.getDao().selectListByOneColumnValue(testId, "testId")
                    .stream().filter(e -> !StringUtils.equals(e.getSyncAnalyteFlag(), Constant.YES)).collect(Collectors.toList());

            orderTaskSupplementBeans.removeIf(os -> testSupplementBeans.stream().anyMatch(ts -> StringUtils.equals(ts.getInformation(), os.getFieldName())));

            if (!orderTaskSupplementBeans.isEmpty()) {
                insertList.parallelStream().forEach(r -> {
                    orderTaskSupplementBeans.stream().filter(rb -> rb.getOrderTaskId().equals(r.getOrderTaskId())
                                    && StringUtils.equalsIgnoreCase(rb.getFieldName(), r.getAnalyte()))
                            .forEach(s -> {
                                r.setOriginalResult(s.getFieldValue());
                                r.setFinalResult(s.getFieldValue());
                                r.setStatus("done");
                            });
                });
            }
            //查找上一步工序的分析项，将相同结果同步过来
            MapperParameter parameter = new MapperParameter();
            parameter.put("orderTaskIds", StringUtils.join(orderTaskIds, ","));
            List<LimsResultBean> resultBeans = selectTopResultValueList(parameter);
            if (!resultBeans.isEmpty()) {
                insertList.parallelStream().forEach(r -> {
                    resultBeans.stream().filter(rb -> StringUtils.equalsIgnoreCase(rb.getAnalyte(), r.getAnalyte())
                                    && StringUtils.equals(rb.getExt$Item("ordtaskid"), String.valueOf(r.getOrderTaskId()))
                                    // 当前新插入的分析项需要继承上一步工序同分析项的值（是否继承-是）
                                    && StringUtils.equals(Constant.YES, r.getInherit()))
                            .forEach(s -> {
                                r.setOriginalResult(s.getOriginalResult());
                                if (!StringUtils.isBlank(s.getPicture())) {
                                    // 要求如果被继承的分析项有修约规则，那新分析项继承修约计算后的值
                                    r.setOriginalResult(s.getFinalResult());
                                }
                                r.setFinalResult(s.getFinalResult());
                                r.setStatus("done");
                            });
                });
            }
            if (!CollectionUtils.isEmpty(insertList)) {
                getDao().fastInsert(insertList);
                //分析项继承上一步工序后，触发公式计算
                OrderTaskResultComputingEngine.getEngine(insertList.stream().map(LimsResultBean::getFolderId).distinct().collect(Collectors.toList())).compute();
                // ExecutorHelper.submit(() -> OrderTaskResultComputingEngine.getEngine(insertList.stream().map(LimsResultBean::getFolderId).distinct().collect(Collectors.toList())).compute());
            }
        }
    }

    private List<LimsResultBean> getResultByOrderTaskAndAnalyte2(LimsOrderTaskBean orderTask, List<LimsTestMethodAnalyteBean> analyteList) {
        List<LimsResultBean> list = new ArrayList<>();
        for (LimsTestMethodAnalyteBean analyte : analyteList) {
            LimsResultBean resultBean = new LimsResultBean();
            // 复制分析项数据
            BeanUtils.copyProperties(analyte, resultBean, new String[]{"id", "status", "createdById", "createdByName", "createdTime", "createdByOrgId", "createdByOrgName"});
//            resultBean.setId(ApplicationContextHelper.getNextIdentity());
            resultBean.setOrderTaskId(orderTask.getId());
            resultBean.setOriginalResult(analyte.getDefaultResult());
            resultBean.setFinalResult(analyte.getDefaultResult());

            resultBean.setOrderId(orderTask.getOrderId());
            resultBean.setFolderId(orderTask.getFolderId());
            resultBean.setAnalyteId(analyte.getId());
            resultBean.setCalcFlag(StringUtils.isEmpty(analyte.getFormula()) ? Constant.NO : Constant.YES);

            list.add(resultBean);
        }
        return list;
    }

    private List<LimsResultBean> selectTopResultValueList(MapperParameter parameter) {
        List<Map<String, Object>> maps = getDao().selectTopResultValueList(parameter);
        return maps.isEmpty() ? Collections.emptyList() :
                maps.stream().map(e -> PersistableHelper.mapToPersistable(e, LimsResultBean.class)).collect(Collectors.toList());
    }

    public List<LimsResultDTO> selectForFormula(MapperParameter parameter) {
        List<Map<String, Object>> maps = getDao().selectForFormula(parameter);
        return maps.isEmpty() ? Collections.emptyList() :
                maps.stream().map(e -> PersistableHelper.mapToPersistable(e, LimsResultDTO.class)).collect(Collectors.toList());
    }

    @Override
    public Page<LimsResultBean> selectResultToColumns(Long runId, RestJsonWrapperBean wrapperBean) {
        wrapperBean.removePageParams();
        MapperParameter parameter = wrapperBean.extractMapFilter();
        parameter.put("runId", runId);
        PageRowBounds pageRowBounds = wrapperBean.extractPageRowBounds();
        Page<LimsResultBean> page = this.selectPagination(() -> getDao().selectResultToColumns(parameter), pageRowBounds);
        if (page.getRows().isEmpty()) {
            return page;
        }
        List<LimsResultBean> itemList = page.getRows();
        // 获取备选结果列表
        if (!itemList.isEmpty()) {
            List<LimsPossibleResultBean> possibleResultBeanList = possibleResultService.selectListByFilter(SearchFilter.instance()
                    .match("analyteId", itemList.stream().map(LimsResultBean::getAnalyteId).distinct().collect(Collectors.toList())).filter(MatchPattern.OR));
            itemList.forEach(resultBean -> {
                List<LimsPossibleResultBean> possibleResultList = possibleResultBeanList.stream().filter(p ->
                        p.getAnalyteId().equals(resultBean.getAnalyteId())).collect(Collectors.toList());
                if (!possibleResultList.isEmpty()) {
                    resultBean.setExt$Item("possibleresultinfo", JSONObject.toJSONString(possibleResultList));
                }
            });
        }
        return new Pagination<>(page, itemList);
    }

    @Override
    @AuditTrailEntry(AuditTrailType.UPDATE)
    @Transactional
    public void updateResultByOrderTaskAndAnalyte(Long orderTaskId, RestJsonWrapperBean wrapperBean) {
        LimsResultBean result = wrapperBean.parseUnique(LimsResultBean.class);

        LimsResultBean searchBean = new LimsResultBean();
//        BeanUtils.copyProperties(result, searchBean, "originalResult");
        searchBean.setAnalyteId(result.getAnalyteId());
        searchBean.setOrderTaskId(orderTaskId);
        List<LimsResultBean> resultList = getDao().selectList(searchBean);
        String original = resultList.get(0).getOriginalResult();
        String calcFlag = resultList.get(0).getCalcFlag();
        if (StringUtils.isBlank(original) || !original.equals(result.getOriginalResult())) {
            resultList.forEach(resultBean -> {
                String originalResult = result.getOriginalResult();
                resultBean.setOriginalResult(originalResult);
                resultBean.setFinalResult(originalResult);
            });
            getDao().fastUpdate(resultList, "ORIGINALRESULT", "FINALRESULT");
            // 计算 --新增公式分析项可编辑，故编辑带公式的分析项不触发计算公式
            // 又改成不可以编辑
//            if (StringUtils.equals(calcFlag, Constant.NO)) {
            OrderTaskResultComputingEngine.getEngine(resultList.stream().map(LimsResultBean::getFolderId).distinct().collect(Collectors.toList()), "com.sunwayworld.baseline.business.ordertask.computing.formula.OrderTaskFormulaRepository").compute();
//            }
            // 结果追溯记录
            CoreAuditTrailRecordLineBean coreAuditTrailRecordLineBean = new CoreAuditTrailRecordLineBean();
            coreAuditTrailRecordLineBean.setId(ApplicationContextHelper.getNextIdentity());
            coreAuditTrailRecordLineBean.setRecordId(orderTaskId);
            coreAuditTrailRecordLineBean.setTableName(getDao().getTable());
            coreAuditTrailRecordLineBean.setTargetId(getDao().getTable() + "$" + resultList.get(0).getId());
            coreAuditTrailRecordLineBean.setRecordType("UPDATE");
            coreAuditTrailRecordLineBean.setColumn("ORIGINALRESULT");
            coreAuditTrailRecordLineBean.setOldValue(original);
            coreAuditTrailRecordLineBean.setNewValue(result.getOriginalResult());
            coreAuditTrailRecordLineService.getDao().insert(coreAuditTrailRecordLineBean);
        }
    }

    @Override
    public List<LimsOrderTaskBean> selectResultByJudgeType(MapperParameter temp) {
        List<Map<String, Object>> maps = getDao().selectResultByJudgeType(temp);
        return maps.isEmpty() ? CollectionUtils.emptyList() :
                maps.stream().map(e -> PersistableHelper.mapToPersistable(e, LimsOrderTaskBean.class)).collect(Collectors.toList());
    }

    @Override
    public LimsResultBean selectDetailByTaskAndAnalyte(Long taskId, Long analyteId) {
        return selectFirstByFilter(SearchFilter.instance().match("orderTaskId", taskId).filter(MatchPattern.EQ)
                .match("analyteId", analyteId).filter(MatchPattern.EQ));
    }

    @Override
    /*
     * 分析项-查询分析项结果
     *     如果是富文本，则显示为“详情”
     * */
    public Page<LimsResultBean> selectCustomResult(RestJsonWrapperBean wrapper) {
        Page<LimsResultBean> resultPage = selectPagination(wrapper);
        List<LimsResultBean> results = resultPage.getRows();
        if (CollectionUtils.isEmpty(results)) {
            return new Pagination<>(Collections.emptyList());
        }
        results.forEach(u -> {
            if ("F".equalsIgnoreCase(u.getAnalType())) {
                u.setFinalResult("详情");
            }
        });
        Page<LimsResultBean> returnPage = new Pagination<>(results);
        return returnPage;
    }

    @Override
    public Page<CoreAuditTrailRecordLineBean> selectRecordLineList(String tableName, String id) {
        MapperParameter parameter = new MapperParameter();
        parameter.put("tableName", tableName);
        parameter.put("recordId", id);
        List<CoreAuditTrailRecordLineBean> limsOrderTaskList = getDao().selectRecordLineList(parameter)
                .stream()
                .map(m -> PersistableHelper.mapToPersistable(m, CoreAuditTrailRecordLineBean.class))
                .collect(Collectors.toList());
        return new Pagination<>(limsOrderTaskList);
    }

}
